package cn.tedu._03_vehicle.base.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.concurrent.ConcurrentHashMap;

public class RateLimitInterceptor implements HandlerInterceptor {
//    //限定拦截器：60秒内同一个IP地址访问网站次数不能超过3次
//    private static final int MAX_REQUESTS_PRE_MINUTE = 3;//定义次数变量
//    private static final int WINDOW_SIZE_SECOND = 60;//定义固定时间
//    //定义两个结合/*
//    // 一个保存地址和次数
//    // 另外一个保存地址和时间
//    // 都是键值对的形式*/
//    private final ConcurrentHashMap<String ,Integer> clientsCounts = new ConcurrentHashMap<>();
//    private final ConcurrentHashMap<String , LocalDateTime> lastTimes = new ConcurrentHashMap<>();
//    @Override
//    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        String remoteAddr = request.getRemoteAddr();//获取到了这个用户的地址
//        LocalDateTime lastTime = lastTimes.get(remoteAddr);//将该用户的时间记录下来
//        //该IP第一次访问网站或者 距离上一次访问已经超过60s的情况下，计算器归零，访问时间也要更新
//        if (lastTime==null ||LocalDateTime.now().isAfter(lastTime.plusSeconds(WINDOW_SIZE_SECOND))){
//            clientsCounts.put(remoteAddr,0);//初始化地址和次数
//            lastTimes.put(remoteAddr,LocalDateTime.now());//将当前时间设置为初始时间
//        }
//        //如果不是第一次并且距离上次访问时间小于60s
//        //计数器+1，时间不动
//        int count = clientsCounts.merge(remoteAddr,1,Integer::sum);
//        //判断次数是否超过3次
//        if (count>MAX_REQUESTS_PRE_MINUTE){
//            throw new RuntimeException("访问过于频繁");
//        }
//        return true;
//    }
    private static final int MAX_REQUESTS_PER_MINUTE=3;
    private static final int WINDOW_SIZE_SECOND = 60;
    private final ConcurrentHashMap<String,Integer> clientCount = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<String,LocalDateTime> lastTimes = new ConcurrentHashMap<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String remoteAddr = request.getRemoteAddr();
        LocalDateTime localDateTime = lastTimes.get(remoteAddr);
        if (localDateTime==null || LocalDateTime.now().isAfter(localDateTime.plusSeconds(WINDOW_SIZE_SECOND))){
            clientCount.put(remoteAddr,0);
            lastTimes.put(remoteAddr,LocalDateTime.now());
        }
        int count=clientCount.merge(remoteAddr,1,Integer::sum);
        if (count>MAX_REQUESTS_PER_MINUTE){
            throw new RuntimeException("访问过于频繁");
        }
        return true;
    }
}

















